/**
 * 
 */
package it.uniroma3.dia.digraph.view.interpolation.impl;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.graphdrawing.graphml.xmlns.EdgeType;
import org.graphdrawing.graphml.xmlns.GraphType;

import it.uniroma3.dia.digraph.algorithm.utility.Utility;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.StackedTriGraph;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.StackedTriNode;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.barycentric.CombinationGraph;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.barycentric.CombinationNode;
import it.uniroma3.dia.digraph.view.DrawingPanel;
import it.uniroma3.dia.digraph.view.interpolation.Interpolator;
import it.uniroma3.dia.digraph.view.interpolation.NodeView;

/**
 * @author Cionzo
 *
 */
public class BarCoordsInterpolator implements Interpolator {
    


    private DrawingPanel drawingPanel;

    private double step;
    private long pause;
    private long durationMillis;
    private int frameNumber;
    private List<NodeView> drawingNodes;
    private Map<String, NodeView> id2nodes;
    private List<EdgeType> edges;
    private CombinationGraph combinationGraph;
	
	

//	private GraphType oldGraph;

//	private Map<String, NodeView> oldNodePositions;
//	private Map<String, NodeView> currentNodePositions;
//	private Map<String, NodeView> destNodePositions;
	
	private StackedTriGraph source, dest;
	
	
	/**
	 * 
	 */
	public BarCoordsInterpolator() {
	    this(new DrawingPanel());
	}

    /**
	 * @param drawingPanel
	 */
	public BarCoordsInterpolator(DrawingPanel drawingPanel) {
	    this(drawingPanel, 1000);
	}
	
	
	/**
	 * @param dp
	 * @param frameNo
	 */
	public BarCoordsInterpolator(DrawingPanel dp, int frameNo) {
	    this(dp, frameNo, 15000);
	}
	
	/**
	 * @param dp
	 * @param frameNo
	 * @param durationMillis
	 */
	public BarCoordsInterpolator(DrawingPanel dp, int frameNo, long durationMillis) {
	    
	    this.drawingPanel = dp;
	    this.step = 1.0/frameNo;
	    this.pause = (long) (durationMillis / frameNo);
	    this.durationMillis = durationMillis;
	    this.frameNumber = frameNo;
	    
	    this.source = null;
	    this.dest = null;
	    
	    this.drawingNodes = new LinkedList<NodeView>();
	    this.id2nodes = new HashMap<String, NodeView>();
	    this.edges = null;
	    
//	    this.oldGraph = null;
//	    this.oldNodePositions = null;
//	    this.destNodePositions = null;
	}

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#getAnimationDuration()
     */
    @Override
    public long getAnimationDuration() {
	return this.durationMillis;
    }

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#getDrawingPanel()
     */
    @Override
    public DrawingPanel getDrawingPanel() {
	return this.drawingPanel;
    }

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#getFrameNumber()
     */
    @Override
    public int getFrameNumber() {
	return this.frameNumber;
    }
    
    public void interpolate(GraphType g) {
	this.interpolate(this.combinationGraph);
	
    }

 
    public void interpolate(CombinationGraph g) {
	List<CombinationNode> allNodes = g.getAllNodes();
	this.initDrawingnodes(allNodes);
	this.edges = g.getEdges();
	
	for (double t=0; t<1-step; t+=step) {
	    this.updatePositions(t, allNodes);
	    this.notifyPanel();
//	    try {
//		Thread.sleep(500);
//	    }
//	    catch (Exception e) {
//		e.printStackTrace();
//	    }
	}

	
	this.notifyPanel();
	   
	
    }

    /**
     * @param allNodes
     */
    private void initDrawingnodes(List<CombinationNode> allNodes) {
	NodeView current;
	
	for (CombinationNode cnode : allNodes) {
	    current = new NodeView(cnode.getId());
	    this.drawingNodes.add(current);
	    this.id2nodes.put(cnode.getId(), current);
	}
    }

    /**
     * 
     */
    private void notifyPanel() {
	this.drawingPanel.setId2nodes(this.id2nodes);
	this.drawingPanel.setEdges(this.edges);
	try {
		Thread.sleep(pause);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	drawingPanel.repaint();
	
    }

    /**
     * 
     */
  

  

    /**
     * @param t
     * @param allNodes 
     */
    private void updatePositions(double t, List<CombinationNode> allNodes) {
	double rest = 1-t;
	
	CombinationNode node;
	NodeView nv;
	
	for (int index=0;index<allNodes.size(); index++) {
	    node = allNodes.get(index);
	    nv = this.drawingNodes.get(index);
	    nv.setX(node.getX(t, rest));
	    nv.setY(node.getY(t, rest));
	}
    }

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#setAnimationDuration(long)
     */
    @Override
    public void setAnimationDuration(long millis) {
	this.durationMillis = millis;
    }

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#setDrawingPanel(it.uniroma3.dia.digraph.view.DrawingPanel)
     */
    @Override
    public void setDrawingPanel(DrawingPanel panel) {
	this.drawingPanel = panel;
    }

    /* (non-Javadoc)
     * @see it.uniroma3.dia.digraph.view.interpolation.Interpolator#setFrameNumber(int)
     */
    @Override
    public void setFrameNumber(int number) {
	this.frameNumber = number;
    }

    /**
     * @param dest the dest to set
     */
    public void setDest(StackedTriGraph dest) {
	this.dest = dest;
    }

    /**
     * @return the dest
     */
    public StackedTriGraph getDest() {
	return dest;
    }

    /**
     * @param source the source to set
     */
    public void setSource(StackedTriGraph source) {
	this.source = source;
    }

    /**
     * @return the source
     */
    public StackedTriGraph getSource() {
	return source;
    }
    
    public void setCombinationGraph(CombinationGraph g) {
	this.combinationGraph = g;
    }

}
